/*
 * Copyright 2008-2013, David George, Licensed under the Apache License,
 * Version 2.0 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.magneato.utils.parsers;

import java.util.Stack;

import org.apache.commons.lang.StringEscapeUtils;
import org.xml.sax.Attributes;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Turns an XML document into a a tree of HashList nodes starting at the root
 * (unnamed node)
 * 
 * @author David George
 * 
 */
public class HashListContentHandler extends DefaultHandler {
	private Stack<HashList> nodes;
	private HashList root = null;
	private int level = 0;
	private int oldLevel = 0;
	private StringBuilder data;
	private final WikiParser wikiParser;
	private static final String syntaxAttr = "wikiSyntax";

	private String rootName = "content";

	public HashListContentHandler(WikiParser wikiParser) {
		if (wikiParser == null) {
			throw new NullPointerException("Wikiparser is null");
		}
		nodes = new Stack<HashList>();
		this.wikiParser = wikiParser;
	}

	/**
	 * Start a new element. If we are dropping down a level push the current
	 * element onto a stack, if we are coming up a level pop the current element
	 * 
	 * (non-Javadoc)
	 * 
	 * @see org.xml.sax.helpers.DefaultHandler#startElement(java.lang.String,
	 *      java.lang.String, java.lang.String, org.xml.sax.Attributes)
	 */
	public void startElement(String uri, String name, String qName,
			Attributes atts) {
		HashList node = null;

		if (level == oldLevel) {
			if (nodes.empty()) {
				// unnamed root node, this is an exception
				root = new HashList("");
				nodes.push(root);
				rootName = qName;
			} else {
				node = nodes.peek();
				node = node.addNode(qName);
				nodes.push(node);
			}
			level++;
		} else {
			node = nodes.peek();
			node.setValue(data.toString());
			node = node.addNode(qName);
			nodes.push(node);
			oldLevel = level;
		}
		if (node != null) {
			// we added a new node
			for (int i = 0; i < atts.getLength(); i++) {
				node.addAttribute(atts.getLocalName(i), atts.getValue(i));
			}
		}
		data = new StringBuilder();
	}

	public String getRootName() {
		return rootName;
	}

	public void endElement(String uri, String name, String qName) {
		level--;
		HashList node = nodes.pop();

		String wikiSyntax = node.getAttribute(syntaxAttr);

		if (wikiSyntax == null) {
			// escape any html, use a sanitizer as the wikiSyntax below if you
			// just want to sanitize HTML
			String text = data.toString();
			if (!(text.trim()).isEmpty()) {
				node.setValue(StringEscapeUtils.escapeXml(data.toString()));
			}
		} else {
			// only parse elements marked at wikiText, note we may allow
			// different parsers
			wikiSyntax = "Confluence"; // TODO hard code for now
			node.setValue(wikiParser.parseLinks(data, wikiSyntax));
		}
		data = new StringBuilder();
	}

	/**
	 * remove extraneous whitespace
	 */
	public void characters(char[] chars, int start, int length) {
		data.append(new String(chars, start, length));
	}

	public HashList getRootNode() {
		return root;
	}
}
